package com.cencat.user.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.cencat.common.response.ApiResponse;
import com.cencat.common.response.PageResponse;
import com.cencat.common.exception.BusinessException;
import com.cencat.user.dto.RoleCreateDTO;
import com.cencat.user.dto.RoleQueryDTO;
import com.cencat.user.dto.RoleUpdateDTO;
import com.cencat.user.service.RoleService;
import com.cencat.user.vo.RoleListVO;
import com.cencat.user.vo.RoleVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.util.List;

/**
 * 角色管理控制器
 * @author cencat
 * @since 2024-01-01
 */
@RestController
@RequestMapping("/api/role")
@Tag(name = "角色管理", description = "角色管理相关接口")
@Slf4j
@Validated
public class RoleController {

    @Autowired
    private RoleService roleService;

    /**
     * 创建角色
     * @param dto 角色创建DTO
     * @return 角色ID
     */
    @PostMapping("/create")
    @Operation(summary = "创建角色", description = "创建新的角色")
    public ApiResponse<Long> createRole(@Valid @RequestBody RoleCreateDTO dto) {
        try {
            Long roleId = roleService.createRole(dto);
            return ApiResponse.success(roleId);
        } catch (BusinessException e) {
            log.error("创建角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 更新角色
     * @param dto 角色更新DTO
     * @return 是否成功
     */
    @PutMapping("/update")
    @Operation(summary = "更新角色", description = "更新角色信息")
    public ApiResponse<Boolean> updateRole(@Valid @RequestBody RoleUpdateDTO dto) {
        try {
            Boolean result = roleService.updateRole(dto);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("更新角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 删除角色
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 是否成功
     */
    @DeleteMapping("/delete/{roleId}")
    @Operation(summary = "删除角色", description = "删除指定角色")
    public ApiResponse<Boolean> deleteRole(
            @Parameter(description = "角色ID", required = true) @PathVariable @Min(1) Long roleId,
            @Parameter(description = "租户ID", required = true) @RequestHeader("tenantId") @NotNull Long tenantId) {
        try {
            Boolean result = roleService.deleteRole(roleId, tenantId);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("删除角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 批量删除角色
     * @param roleIds 角色ID列表
     * @param tenantId 租户ID
     * @return 是否成功
     */
    @DeleteMapping("/batch-delete")
    @Operation(summary = "批量删除角色", description = "批量删除指定角色")
    public ApiResponse<Boolean> batchDeleteRoles(
            @Parameter(description = "角色ID列表", required = true) @RequestBody @NotEmpty List<Long> roleIds,
            @Parameter(description = "租户ID", required = true) @RequestHeader("tenantId") @NotNull Long tenantId) {
        try {
            Boolean result = roleService.batchDeleteRoles(roleIds, tenantId);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("批量删除角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 根据ID查询角色详情
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 角色详情
     */
    @GetMapping("/detail/{roleId}")
    @Operation(summary = "查询角色详情", description = "根据ID查询角色详情")
    public ApiResponse<RoleVO> getRoleById(
            @Parameter(description = "角色ID", required = true) @PathVariable @Min(1) Long roleId,
            @Parameter(description = "租户ID", required = true) @RequestHeader("tenantId") @NotNull Long tenantId) {
        try {
            RoleVO roleVO = roleService.getRoleById(roleId, tenantId);
            return ApiResponse.success(roleVO);
        } catch (BusinessException e) {
            log.error("查询角色详情失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 分页查询角色列表
     * @param queryDTO 查询条件
     * @return 角色分页列表
     */
    @PostMapping("/page")
    @Operation(summary = "分页查询角色列表", description = "根据条件分页查询角色列表")
    public ApiResponse<PageResponse<RoleListVO>> getRolePage(@Valid @RequestBody RoleQueryDTO queryDTO) {
        try {
            PageResponse<RoleListVO> rolePage = roleService.getRolePage(queryDTO);
            return ApiResponse.success(rolePage);
        } catch (BusinessException e) {
            log.error("分页查询角色列表失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 查询角色列表
     * @param queryDTO 查询条件
     * @return 角色列表
     */
    @PostMapping("/list")
    @Operation(summary = "查询角色列表", description = "根据条件查询角色列表")
    public ApiResponse<List<RoleListVO>> getRoleList(@Valid @RequestBody RoleQueryDTO queryDTO) {
        try {
            List<RoleListVO> result = roleService.getRoleList(queryDTO);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("查询角色列表失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 启用角色
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @param operatorId 操作人ID
     * @return 是否成功
     */
    @PutMapping("/enable/{roleId}")
    @Operation(summary = "启用角色", description = "启用指定角色")
    public ApiResponse<Boolean> enableRole(
            @Parameter(description = "角色ID", required = true) @PathVariable @Min(1) Long roleId,
            @Parameter(description = "租户ID", required = true) @RequestHeader("tenantId") @NotNull Long tenantId,
            @Parameter(description = "操作人ID", required = true) @RequestHeader("operatorId") @NotNull Long operatorId) {
        try {
            Boolean result = roleService.enableRole(roleId, tenantId, operatorId);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("启用角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 禁用角色
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @param operatorId 操作人ID
     * @return 是否成功
     */
    @PutMapping("/disable/{roleId}")
    @Operation(summary = "禁用角色", description = "禁用指定角色")
    public ApiResponse<Boolean> disableRole(
            @Parameter(description = "角色ID", required = true) @PathVariable @Min(1) Long roleId,
            @Parameter(description = "租户ID", required = true) @RequestHeader("tenantId") @NotNull Long tenantId,
            @Parameter(description = "操作人ID", required = true) @RequestHeader("operatorId") @NotNull Long operatorId) {
        try {
            Boolean result = roleService.disableRole(roleId, tenantId, operatorId);
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("禁用角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 批量更新角色状态
     * @param request 批量更新请求
     * @return 是否成功
     */
    @PutMapping("/batch-update-status")
    @Operation(summary = "批量更新角色状态", description = "批量更新角色状态")
    public ApiResponse<Boolean> batchUpdateRoleStatus(@Valid @RequestBody BatchUpdateStatusRequest request) {
        try {
            Boolean result = roleService.batchUpdateRoleStatus(
                    request.getRoleIds(), 
                    request.getStatus(), 
                    request.getTenantId(), 
                    request.getOperatorId());
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("批量更新角色状态失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 根据用户ID查询角色列表
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 角色列表
     */
    @GetMapping("/user/{userId}")
    @Operation(summary = "查询用户角色", description = "根据用户ID查询角色列表")
    public ApiResponse<List<RoleListVO>> getRolesByUserId(
            @Parameter(description = "用户ID", required = true) @PathVariable @Min(1) Long userId,
            @Parameter(description = "租户ID", required = true) @RequestHeader("tenantId") @NotNull Long tenantId) {
        try {
            List<com.cencat.user.entity.Role> roles = roleService.getRolesByUserId(userId, tenantId);
            List<RoleListVO> result = roles.stream()
                    .map(role -> {
                        RoleListVO vo = new RoleListVO();
                        org.springframework.beans.BeanUtils.copyProperties(role, vo);
                        return vo;
                    })
                    .collect(java.util.stream.Collectors.toList());
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("查询用户角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 为用户分配角色
     * @param request 分配角色请求
     * @return 是否成功
     */
    @PostMapping("/assign-to-user")
    @Operation(summary = "分配角色给用户", description = "为用户分配角色")
    public ApiResponse<Boolean> assignRolesToUser(@Valid @RequestBody AssignRolesRequest request) {
        try {
            Boolean result = roleService.assignRolesToUser(
                    request.getUserId(), 
                    request.getRoleIds(), 
                    request.getTenantId(), 
                    request.getOperatorId());
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("分配角色给用户失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 移除用户角色
     * @param request 移除角色请求
     * @return 是否成功
     */
    @PostMapping("/remove-from-user")
    @Operation(summary = "移除用户角色", description = "移除用户的角色")
    public ApiResponse<Boolean> removeRolesFromUser(@Valid @RequestBody RemoveRolesRequest request) {
        try {
            Boolean result = roleService.removeRolesFromUser(
                    request.getUserId(), 
                    request.getRoleIds(), 
                    request.getTenantId(), 
                    request.getOperatorId());
            return ApiResponse.success(result);
        } catch (BusinessException e) {
            log.error("移除用户角色失败: {}", e.getMessage());
            return ApiResponse.error(e.getErrorCode());
        }
    }

    /**
     * 批量更新状态请求
     */
    @lombok.Data
    public static class BatchUpdateStatusRequest {
        @NotEmpty(message = "角色ID列表不能为空")
        private List<Long> roleIds;
        
        @NotNull(message = "状态不能为空")
        private Integer status;
        
        @NotNull(message = "租户ID不能为空")
        private Long tenantId;
        
        @NotNull(message = "操作人ID不能为空")
        private Long operatorId;
    }

    /**
     * 分配角色请求
     */
    @lombok.Data
    public static class AssignRolesRequest {
        @NotNull(message = "用户ID不能为空")
        private Long userId;
        
        @NotEmpty(message = "角色ID列表不能为空")
        private List<Long> roleIds;
        
        @NotNull(message = "租户ID不能为空")
        private Long tenantId;
        
        @NotNull(message = "操作人ID不能为空")
        private Long operatorId;
    }

    /**
     * 移除角色请求
     */
    @lombok.Data
    public static class RemoveRolesRequest {
        @NotNull(message = "用户ID不能为空")
        private Long userId;
        
        @NotEmpty(message = "角色ID列表不能为空")
        private List<Long> roleIds;
        
        @NotNull(message = "租户ID不能为空")
        private Long tenantId;
        
        @NotNull(message = "操作人ID不能为空")
        private Long operatorId;
    }
}